#pragma once

#include <compl.h>
#include <dbg.h>
#include <dinfra/list.h>


/* 保持自对齐 */
// #define KSLAB_RALIGNED

typedef struct kslab
{
	struct{
		dlist_t node;

		/* 需要加cls嘛? */

		hword_t max_nr;
		hword_t used_nr;

		union{
			
			struct{
				hword_t unit_size;
				szcls_t cls;
			};
			word_t cls_size;
		};
		size_t max_size;
		// 使用编码未满
		slist_t *flist;
		// slist_t *flist_tail;
		size_t used_offst;
		size_t dnode_cnt; /* 释放的时候使用 */
		
	} CACHE_ALIGNED;
} kslab_t;

#define FLIST_NEXT_OFFST (slist_t *)(-1)

SIN void *kslab_get_offst(kslab_t *s, size_t offst)
{
	return (void *)((paddr_t)s + offst);
}
SIN slist_t *kslab_pop_flist(kslab_t *s)
{
	slist_t *ret = s->flist;
	/* 如果flist存在 */
	if (ret)
	{
		// 使用flist标记法,pop前判断下一个
		slist_t *next = ret->next;
		if (next == FLIST_NEXT_OFFST)
		{
			// ASSERT(s->used_nr == s->max_nr);
			// 设置位
			s->flist = (slist_t *)kslab_get_offst(s, s->used_offst);
			s->used_offst += s->unit_size;
			// 判断下一个情况
			s->max_nr++;
			if (s->used_offst + s->unit_size > s->max_size)
			{
				
				s->flist->next = NULL_PTR;
				// s->used_offst = s->max_size;
			}
			else
			{
				s->flist->next = FLIST_NEXT_OFFST;
			}
		}
		else
		{
			// 直接
			s->flist = next;
			
			// if (next == NULL_PTR) ASSERT(s->used_nr + 1 == s->max_nr);
		}
	}
	ASSERT(ret == NULL_PTR || (((paddr_t)ret + s->unit_size - (paddr_t)s) <= s->max_size));
	return ret;
}


SIN kslab_t *kslab_init(void *ptr, size_t slab_size, szcls_t cls, hword_t unit_size)
{
	ASSERT(is_ptr_aligned(ptr, slab_size));
	kslab_t *ret = (kslab_t *)ptr;
	
	// ASSERT(ret->used_nr == 0);
#ifdef KSLAB_RALIGNED
	/* 如何优化掉除法实现呢? */
	size_t used_offst = slab_size - ((slab_size - sizeof(kslab_t)) / unit_size) * unit_size;
	/* 右边界对齐，避免除法，性能有所提升 */
	// size_t used_offst = align_up(sizeof(kslab_t) + unit_size, unit_size) - unit_size; 
	// size_t used_offst = 
#else
	size_t used_offst = align_up(sizeof(kslab_t), HDEF_CACHE_LINE_BYTES);
	if (is_powerof2(unit_size)) used_offst = align_up(used_offst, unit_size); 
#endif
	ret->max_size = slab_size;

	ret->used_nr = 0;

	ret->max_nr = 1;

	ret->cls = cls;
	ret->unit_size = unit_size;

	ret->used_offst = used_offst + unit_size;
	ret->flist = (slist_t *)kslab_get_offst(ret, used_offst);
	ret->flist->next = FLIST_NEXT_OFFST;
	ret->dnode_cnt = 0;

	return ret;
}

// kslab是否满判断
SAI bool_t kslab_is_free(kslab_t *s)
{
	return (s->used_nr == 0);
}
SAI bool_t kslab_is_empty(kslab_t *s)
{
	// return (s->used_nr == s->max_nr) ;
	return (s->flist == NULL_PTR);
	// return (s->flist == NULL) && (s->used_offst == (1UL << s->size_order));
}
// 分配
SIN size_t kslab_alloc_batch(kslab_t *s, slist_t **hptr, slist_t **tptr, size_t request_nr)
{
	// 优先从flist中取
	size_t pop_nr = 0;
	slist_t *hdr = kslab_pop_flist(s);

	if (!hdr) return 0;

	slist_t *cur = hdr;
	slist_t *popped;

	// 循环pop
	// pop_nr = 1;
	// cur->next = NULL;
	while (++pop_nr < request_nr)
	{
		popped = kslab_pop_flist(s);
		// 下一个
		// cur->next = popped;
		if (!popped)
			break;
		// 连接
		cur->next = popped;
		cur = popped;
	}

	cur->next = NULL_PTR;
	ASSERT(cur->next == NULL);
	s->used_nr += pop_nr;
	// ASSERT(slist_len_noloop(hdr) == pop_nr);
	if (!s->flist){ ASSERT(s->used_nr == s->max_nr); };
	// dbg_printf("[kslab] %p alloc batch %u, used_nr %u\n", s, pop_nr, s->used_nr);
	*hptr = hdr;
	*tptr = cur;
	// ASSERT(slist_len_noloop(hdr) == pop_nr);
	return pop_nr;
}

// 分配1

// 释放
SIN kslab_t *kslab_free_batch(kslab_t *s, slist_t *head, slist_t *tail, size_t nr)
{
	ASSERT(is_ptr_aligned(s, s->max_size));
	ASSERT(head == tail);
	slist_t *cur = s->flist;
	tail->next = cur;
	s->flist = head;
	/* 修复问题 */
	s->used_nr -= nr;

	// ASSERT(s->used_offst != s->max_size || slist_len_noloop(head) == s->max_nr - s->used_nr);
	// dbg_printf("[kslab] %p free batch %u, used_nr %u\n", s, nr, s->used_nr);
	if (kslab_is_free(s))
	{
		
		// if (s->used_offst == (1UL << s->size_order)) ASSERT( slist_len_noloop(head) == s->max_nr); 
		// ASSERT(s->used_offst == (1UL << s->size_order) || slist_len_noloop(head) == s->max_nr);
		return s;
	}
	return NULL;
}


